#include <header.h>
#include "linked_list.h"

LinkedList* create_linked_list() {
	LinkedList* list = (LinkedList*)calloc(1, sizeof(LinkedList));
	ERROR_CHECK(list, NULL, "calloc failed in create_linked_list.\n");

	return list;
}
bool add_behind_tail(LinkedList* list, DataType data) {
	Node* node = (Node*)calloc(1, sizeof(Node));
	if (node == NULL) {
		printf("error: calloc failed in add_before_head.\n");
		return 0;
	}
	node->data = data;

	// 尾插	
	if (list->head == NULL) {
		list->head = list->tail = node;
	}else {
		list->tail = list->tail->next = node;
	}
	list->size++;
	return 1;
}
void destroy_linked_list(LinkedList* list) {

	Node* curr = list->head;
	while (curr) {
		Node* t = curr;
		free(t);
		curr = curr->next;
	}

	free(list);
}
bool delete_node_by_data(LinkedList* list, DataType data) {
	Node* predecessor = 0;
	Node* curr = list->head;
	for (; curr && curr->data != data; predecessor = curr, curr = curr->next);

	if (curr) {
		if (curr == list->head) {
			list->head = list->head->next;
		}else{
			predecessor->next = curr->next;
		}

		if (curr == list->tail) {
			list->tail = predecessor;
		}
		list->size--;
		free(curr);
		return 1;
	}
	return 0;
}

void broadcast(LinkedList* linked_users, int net_fd, char *buf, int len){
    Node *curr = linked_users->head;
    while(curr){
        if(curr->data != net_fd){
            send(curr->data, buf, len, 0);
        }
        curr = curr->next;
    }
}


void print_list(LinkedList* list){
	Node* curr = list->head;
	while (curr){
		printf("%d ", curr->data);
		curr = curr->next;
	}
	printf("\n");
	
}

int main(int argc, char* argv[]){
	ARGS_CHECK(argc, 1);

	char *port = "8080";
	char *ip = "192.168.169.128";
	int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
	ERROR_CHECK(socket_fd, -1, "socket");

	// 端口复用
	int reuse = 1;
	setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse);

	// 绑定ip
	struct sockaddr_in serveraddr;
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(atoi(port));
	serveraddr.sin_addr.s_addr = inet_addr(ip);
	int ret_bind = bind(socket_fd, (struct sockaddr*)&serveraddr, sizeof serveraddr);
	ERROR_CHECK(ret_bind, -1, "bind");
	
	// 监听
	int ret_listen = listen(socket_fd, 10);
	ERROR_CHECK(ret_listen, -1, "listen");

    // 创建一个用户链表
    LinkedList* linked_users = create_linked_list();

	int net_fd;
	fd_set set;
	FD_ZERO(&set);	
    

	while(1){
		// 将所有用户添加监听
        Node *p = linked_users->head;
        while(p){
            FD_SET(p->data, &set);
            p = p->next;
        }

		// 每次都要监听socket
        FD_SET(socket_fd, &set);
	    
		int res = select(10, &set, NULL, NULL, NULL);
		ERROR_CHECK(res, -1, "select");
		
        // 有用户连接
		if(FD_ISSET(socket_fd, &set)){
            net_fd = accept(socket_fd, NULL, NULL);
            ERROR_CHECK(net_fd, -1, "accept");
			// 新用户插入链表
            add_behind_tail(linked_users, net_fd);		
		}

        // 有用户广播，则消息群发，需要循环判断
        Node *curr = linked_users->head;
        while(curr){
            if(FD_ISSET(curr->data, &set)){
                net_fd = curr->data;
                break;
            }
            curr = curr->next;
        }
		// 如果curr != NULL 则必有人发消息
        if(curr){
            char buf[1 << 10] = {0};            
            __bzero(buf, sizeof buf);
            ssize_t byte = recv(net_fd, buf, sizeof buf, 0);
            ERROR_CHECK(byte, -1, "recv");
            
            // 对方关闭，读取到0
            if(byte == 0){
				// 不清空会报错
				FD_CLR(net_fd, &set);
                delete_node_by_data(linked_users, net_fd);  
				close(net_fd);                  
                continue;
            }

			printf("log %d:%s\n", net_fd, buf);
            // 广播,自己不发
            broadcast(linked_users, net_fd, buf, sizeof buf);
        }

	}
	destroy_linked_list(linked_users);
	close(socket_fd);
	return 0;
}